﻿#region Apache 2.0 License header

//   Copyright 2012 Lesley van Zijl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. 

#endregion

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using FavourObjects;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Tests.Helpers;

namespace Tests
{
    [TestClass]
    public class MethodTests
    {
        #region Private basic method

        [TestMethod]
        public void Private_Void_Method_void()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethod>(new TargetTestClass());

            favourObject.Method();
        }

        [TestMethod]
        public void PrivateStatic_void_Method_void()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethod>(new TargetTestClass());

            favourObject.MethodStatic();
        }

        public interface IPrivateVoidMethod
        {
            void Method();
            void MethodStatic();
        }

        #endregion

        #region Private Methods with value types

        [TestMethod]
        public void Private_Void_Method_ValueType()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodValueTypeArgs>(new TargetTestClass());

            favourObject.Method1ParameterValueType(5);
        }

        [TestMethod]
        public void Private_Void_Method_2ValueTypes()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodValueTypeArgs>(new TargetTestClass());

            favourObject.Method2ParameterValueType(5, 0.5f);
        }

        [TestMethod]
        public void Private_ValueType_Method_void()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodValueTypeArgs>(new TargetTestClass());

            Assert.AreEqual(5, favourObject.MethodValueReturn());
        }

        [TestMethod]
        public void Private_Void_Method_Guid()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodValueTypeArgs>(new TargetTestClass());

            var guid = new Guid();
            Assert.AreEqual(Guid.Empty, favourObject.MethodGuidArg(ref guid));
        }

        public interface IPrivateVoidMethodValueTypeArgs
        {
            void Method1ParameterValueType(int i);
            void Method2ParameterValueType(int i, float f);
            int MethodValueReturn();
            Guid MethodGuidArg(ref Guid guid);
        }

        #endregion

        #region Private Methods with reference types

        [TestMethod]
        public void Private_Void_Method_RefType()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodRefTypeArgs>(new TargetTestClass());

            favourObject.Method1ParameterReferenceType(new DynamicMethod("F", null, Type.EmptyTypes));
        }

        [TestMethod]
        public void Private_Void_Method_2RefTypes()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodRefTypeArgs>(new TargetTestClass());

            favourObject.Method2ParamaterReferenceType(new DynamicMethod("F", null, Type.EmptyTypes),
                                                       new StringBuilder());
        }

        [TestMethod]
        public void Private_ReferenceType_Method_void()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodRefTypeArgs>(new TargetTestClass());

            MethodInfo methodInfo = favourObject.MethodReferenceReturn();

            Assert.AreEqual(typeof (double), methodInfo.ReturnType);
        }

        public interface IPrivateVoidMethodRefTypeArgs
        {
            void Method1ParameterReferenceType(MethodInfo methodInfo);
            void Method2ParamaterReferenceType(MethodInfo methodInfo, StringBuilder stringBuilder);
            MethodInfo MethodReferenceReturn();
        }

        #endregion

        #region Private Methods with arrays as parameters

        [TestMethod]
        public void Private_Void_Method_ArrayValueTypes()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodArrayArgs>(new TargetTestClass());

            int result = favourObject.MethodValueTypeArray(new[] {1, 2, 3, 4, 5});

            Assert.AreEqual(15, result);
        }

        [TestMethod]
        public void Private_Void_Method_ArrayReferenceTypes()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodArrayArgs>(new TargetTestClass());

            favourObject.MethodReferenceTypeArray(new MethodInfo[]
                                                      {
                                                          new DynamicMethod("F", null, Type.EmptyTypes),
                                                      });
        }

        [TestMethod]
        public void Private_Void_Method_2Arrays()
        {
            var favourObject = FavourObject.Create<IPrivateVoidMethodArrayArgs>(new TargetTestClass());

            favourObject.Method2Arrays(new[] {1, 2, 3, 4, 5},
                                       new MethodInfo[]
                                           {
                                               new DynamicMethod("F", null, Type.EmptyTypes),
                                           });
        }

        public interface IPrivateVoidMethodArrayArgs
        {
            int MethodValueTypeArray(int[] ints);
            void MethodReferenceTypeArray(MethodInfo[] methods);
            void Method2Arrays(int[] ints, MethodInfo[] methods);
        }

        #endregion

        #region Private Methods with overloads

        [TestMethod]
        public void Private_MethodOverloads()
        {
            var favourObject = FavourObject.Create<IPrivateMethodOverloads>(new TargetTestClass());

            favourObject.MethodOverload();
            favourObject.MethodOverload(5);
            favourObject.MethodOverload(5, 6.0);
            favourObject.MethodOverload(6, new DynamicMethod("F", typeof (void), Type.EmptyTypes));
            favourObject.MethodOverload(new DynamicMethod("F", typeof(void), Type.EmptyTypes));
        }

        public interface IPrivateMethodOverloads
        {
            void MethodOverload();
            void MethodOverload(int i);
            void MethodOverload(int i, double d);
            void MethodOverload(int i, MethodInfo mi);
            void MethodOverload(MethodInfo mi);
        }

        #endregion
    }
}